Column.render   A
last analyzed

Complexity

Conditions 4

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
dl 0
loc 15
rs 9.8
c 0
b 0
f 0
1
import React from 'react';
2
import PropTypes from 'prop-types';
3
import {
4
  Table as BSTable,
5
  Checkbox,
6
} from 'react-bootstrap';
7
8
class Column extends React.Component {
9
  render() {
10
    let content = this.props.options.key ? this.props.item[this.props.options.key] : '';
11
    if (typeof this.props.options.display === 'function') {
12
      const displayResult = this.props.options.display(this.props.item);
13
      if (displayResult instanceof Promise) {
14
        displayResult.then((content) => {
15
          React.Children.map(this.props.children, (child => React.cloneElement(child, {}, content)));
16
        }).catch((error) => {
17
          React.Children.map(this.props.children, (child => React.cloneElement(child, {}, error.message)));
18
        });
19
      } else {
20
        content = displayResult;
21
      }
22
    }
23
    return <td>{content}</td>;
24
  }
25
}
26
Column.propTypes = {
27
  item: PropTypes.object.isRequired,
28
  options: PropTypes.shape({
29
    key: PropTypes.string,
30
    display: PropTypes.func,
31
  }).isRequired,
32
};
33
34
class Row extends React.Component {
35
  onCheckboxChanged(checked, item) {
36
    this.props.onCheckboxChange(checked, item);
37
  }
38
39
  render() {
40
    return (
41
      <tr
42
        className={`${this.props.className} ${this.props.checked ? 'checked-row' : ''}`}
43
        onClick={() => this.onCheckboxChanged(!this.props.checked, this.props.item)}
44
      >
45
        {this.props.showCheckbox ? (
46
          <td><Checkbox onChange={e => this.onCheckboxChanged(e.target.checked, this.props.item)} checked={this.props.checked} /></td>
47
        ) : ''}
48
        {this.props.columns.map((col, idx) => <Column key={idx} item={this.props.item} options={col} />)}
49
      </tr>
50
    );
51
  }
52
}
53
Row.propTypes = {
54
  item: PropTypes.object.isRequired,
55
  columns: PropTypes.arrayOf(PropTypes.shape({
56
    key: PropTypes.string,
57
    display: PropTypes.func,
58
    isChildRow: PropTypes.bool,
59
    title: PropTypes.string,
60
  })).isRequired,
61
  checked: PropTypes.bool,
62
  onCheckboxChange: PropTypes.func,
63
  className: PropTypes.string,
64
  showCheckbox: PropTypes.bool,
65
};
66
67
class ChildRow extends React.Component {
68
  render() {
69
    return (
70
      <tr className={`${this.props.checked ? 'checked-row' : ''}`}>
71
        {this.props.showCheckbox ? <td /> : ''}
72
        <td colSpan={this.props.colSpan}>
73
          <BSTable bsClass="table inner-table">
74
            <colgroup>
75
              <col style={{ width: '100px' }} />
76
              <col />
77
            </colgroup>
78
            <tbody>
79
              {this.props.columns.map((col, idx) => {
80
                return <tr key={idx}><th>{col.title}</th><Column item={this.props.item} options={col} /></tr>;
81
              })}
82
            </tbody>
83
          </BSTable>
84
        </td>
85
      </tr>
86
    );
87
  }
88
}
89
ChildRow.propTypes = {
90
  item: PropTypes.object.isRequired,
91
  columns: PropTypes.arrayOf(PropTypes.shape({
92
    key: PropTypes.string,
93
    display: PropTypes.func,
94
    isChildRow: PropTypes.bool,
95
    title: PropTypes.string,
96
  })).isRequired,
97
  checked: PropTypes.bool,
98
  colSpan: PropTypes.number,
99
  showCheckbox: PropTypes.bool,
100
};
101
102
export default class Table extends React.Component {
103
  constructor(props) {
104
    super(props);
105
106
    this.state = {
107
      allChecked: false,
108
      checkedItems: [],
109
    };
110
  }
111
112
  setChecked(checked, item) {
113
    this.onCheckboxChanged(checked, item);
114
  }
115
116
  getChecked() {
117
    return this.state.checkedItems;
118
  }
119
120
  onCheckboxChanged(checked, targetItem) {
121
    let checkedItems = this.state.checkedItems;
122
    let allChecked = this.state.allChecked;
123
    if (!targetItem) {  // all
124
      checkedItems = checked ? this.props.items.slice(0) : [];
125
      allChecked = checked;
126
    } else {
127
      if (checked) {
128
        checkedItems = checkedItems.concat(targetItem);
129
        if (checkedItems.length === this.props.items.length) {
130
          allChecked = true;
131
        }
132
      } else {
133
        const idx = checkedItems.indexOf(targetItem);
134
        if (idx > -1) {
135
          checkedItems.splice(idx, 1);
136
          allChecked = false;
137
        }
138
      }
139
    }
140
    this.setState({ checkedItems, allChecked });
141
    this.props.onCheckboxChange(checkedItems);
142
  }
143
144
  render() {
145
    const self = this;
146
    const mainCols = this.props.columns.filter(column => !column.isChildRow);
147
    const childCols = this.props.columns.filter(column => column.isChildRow);
148
149
    const mainColsLength = this.props.showCheckbox ? mainCols.length + 1 : mainCols.length;
150
151
    let rows = <tr><td colSpan={mainColsLength} style={{ 'text-align': 'center' }}>아이템이 없습니다.</td></tr>;
152
    if (this.props.items.length > 0) {
153
      rows = this.props.items.map((item, idx) => {
154
        const checked = self.state.checkedItems.includes(item);
155
        if (childCols.length > 0) {
156
          return [
157
            <Row
158
              className="main-row"
159
              key={idx}
160
              item={item}
161
              columns={mainCols}
162
              onCheckboxChange={(isChecked, targetItem) => this.onCheckboxChanged(isChecked, targetItem)}
163
              checked={checked}
164
              showCheckbox={this.props.showCheckbox}
165
            />,
166
            <ChildRow
167
              item={item}
168
              columns={childCols}
169
              colSpan={mainCols.length}
170
              checked={checked}
171
              showCheckbox={this.props.showCheckbox}
172
            />,
173
          ];
174
        }
175
        return (
176
          <Row
177
            key={idx}
178
            item={item}
179
            columns={mainCols}
180
            onCheckboxChange={(isChecked, targetItem) => this.onCheckboxChanged(isChecked, targetItem)}
181
            checked={checked}
182
            showCheckbox={this.props.showCheckbox}
183
          />
184
        );
185
      });
186
    }
187
188
    return (
189
      <BSTable responsive>
190
        <thead>
191
          <tr>
192
            {this.props.showCheckbox ? (
193
              <th>
194
                <Checkbox onChange={e => this.onCheckboxChanged(e.target.checked)} checked={this.state.allChecked} />
195
              </th>
196
            ) : ''}
197
            {mainCols.map((col, idx) => <th key={idx}>{col.title}</th>)}
198
          </tr>
199
        </thead>
200
        <tbody>{rows}</tbody>
201
      </BSTable>
202
    );
203
  }
204
}
205
206
Table.defaultProps = {
207
  onCheckboxChange: () => {},
208
  showCheckbox: false,
209
};
210
211
Table.propTypes = {
212
  items: PropTypes.arrayOf(PropTypes.object).isRequired,
213
  columns: PropTypes.arrayOf(PropTypes.shape({
214
    key: PropTypes.string,
215
    display: PropTypes.func,
216
    isChildRow: PropTypes.bool,
217
    title: PropTypes.string,
218
  })).isRequired,
219
  onCheckboxChange: PropTypes.func,
220
  showCheckbox: PropTypes.bool,
221
};
222